using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

namespace Microsoft.PowerShell.CmdletManagement.CompareCmdlet
{
    public class PsSpecCmdletParameterData : PsSpecCmdletParameter
    {
        private int _position;
        private bool _mandatory;
        private bool _valueFromPipeline;
        private bool _valueFromPipelineByPropertyName;
        private MemberInfo _memberInfo;
        private NonameParameterSet _parameterSet;
        List<IMismatch> _mismatches = new List<IMismatch>();

        public PsSpecCmdletParameterData() {}

        public PsSpecCmdletParameterData(
            PsSpecCmdletService.PsSpecCmdletParameter parameter,
            PsSpecCmdletService.PsSpecCmdletParameterSetEntry entry)
            : base(parameter.Id, parameter.ProjectName, parameter.CmdletName, parameter.Name, parameter.Type,
                        parameter.Description, parameter.Alias,
                        parameter.AllowGlobbing, parameter.AllowMultiple,
                        parameter.IsDynamic, parameter.AllowEmptyCollection, parameter.AllowEmptyString, parameter.AllowNull,
                        parameter.ValidateCount, parameter.ValidateNotNull, parameter.ValidateNotNullOrEmpty, 
                        parameter.ValidateRange, parameter.ValidateSet, parameter.ValidateLength, 
                        parameter.ValidatePattern, parameter.Note, parameter.DefaultValue,
                        parameter.Custom1, parameter.Custom2, parameter.Custom3, parameter.Custom4,
                        parameter.HelpDescription)
        {
            _mandatory = entry.Mandatory;
            _position = entry.Position.HasValue ? entry.Position.Value : -1; // -1 means Named position
            _valueFromPipeline = entry.ValueFromPipeline;
            _valueFromPipelineByPropertyName = entry.ValueFromPipelineByPropertyName;
        }

        public bool Mandatory
        {
            get { return _mandatory; }
            set { _mandatory = value; }
        }

        public int Position
        {
            get { return _position; }
            set { _position = value; }
        }

        public bool ValueFromPipeline
        {
            get { return _valueFromPipeline; }
            set { _valueFromPipeline = value; }
        }

        public bool ValueFromPipelineByPropertyName
        {
            get { return _valueFromPipelineByPropertyName; }
            set { _valueFromPipelineByPropertyName = value; }
        }

        public MemberInfo MemberInfo
        {
            get { return _memberInfo; }
            set { _memberInfo = value; }
        }

        public NonameParameterSet ParameterSet {
            get {return _parameterSet;}
            set {_parameterSet = value;}
        }

        public bool HasName(PsSpecCmdletParameterData parameter) {
            return Name.Equals(parameter.Name, StringComparison.OrdinalIgnoreCase);
        }

        public void CompareToImplementation(PsSpecCmdletParameterData implementedParameter) {
            if (this._valueFromPipeline != implementedParameter._valueFromPipeline) {
                _mismatches.Add(new ParameterMismatch(this, "ValueFromPipeline", _valueFromPipeline.ToString(), implementedParameter._valueFromPipeline.ToString()));
            }
            if (this._valueFromPipelineByPropertyName != implementedParameter._valueFromPipelineByPropertyName) {
                _mismatches.Add(new ParameterMismatch(this, "ValueFromPipelineByPropertyName", _valueFromPipelineByPropertyName.ToString(), implementedParameter._valueFromPipelineByPropertyName.ToString()));
            }
            if (this._mandatory != implementedParameter._mandatory) {
                _mismatches.Add(new ParameterMismatch(this, "Mandatory", _mandatory.ToString(), implementedParameter._mandatory.ToString()));
            }
            if ((this._position < 0 && implementedParameter._position >= 0) ||
                (this._position >= 0 && implementedParameter._position < 0) ||
                (this._position >= 0 && implementedParameter._position >= 0 && this._position != implementedParameter._position))
            {
                string implemented, specified;
                if(implementedParameter._position < 0)
                    implemented = "Named";
                else
                    implemented = implementedParameter._position.ToString();
                if(this._position < 0)
                    specified = "Named";
                else
                    specified = this._position.ToString();
                _mismatches.Add(new ParameterMismatch(this, "Position", specified, implemented));
            }
            string[] partialFullName = implementedParameter.Type.Split(',');
            string partialName = partialFullName[0];
            string fullName = partialFullName[1];

            if (String.Compare(this.Type, fullName) != 0 && String.Compare(this.Type, partialName) != 0)
            {
                _mismatches.Add(new ParameterMismatch(this, "Type", Type, fullName));
            }
        }

		///<summary>Returns a total number of errors in this cmdlet</summary>
		public int CountMismatches() {
			return _mismatches.Count;
		}

		///<summary>Returns a total number of errors in this cmdlet</summary>
		public int CountMismatches(int counter) {
            foreach(IMismatch mismatch in _mismatches) {
                counter = mismatch.CountMismatches(counter);
            }
			return counter;
		}

        public void AddMismatchesToList(List<IMismatch> store) {
            store.AddRange(_mismatches);
        }

        public void SortMismatches(List<IMismatch> highList, List<IMismatch> warningList) {
            // Sort mismatches on the parameter level
            foreach(IMismatch mismatch in _mismatches) {
                mismatch.AddMismatch(highList);
                mismatch.AddMismatch(warningList);
            }
        }
    }
}
